import json
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

class ItemPricingStrategy:
    def __init__(self):
        """饰品定价策略分析器，用于分析价格趋势和计算捡漏阈值"""
        pass

    @staticmethod
    def _find_optimal_clusters(X, max_clusters=6):
        """使用轮廓系数来寻找最优聚类数量"""
        if len(X) < 10:  # 数据太少，直接返回2
            return 2
            
        silhouette_scores = []  # 轮廓系数
        
        # 尝试不同的聚类数量
        for k in range(2, min(max_clusters + 1, len(X))):
            if k >= len(X):  # 聚类数不能等于或超过样本数
                break
                
            kmeans = KMeans(n_clusters=k, random_state=42)
            kmeans.fit(X)
            score = silhouette_score(X, kmeans.labels_)
            silhouette_scores.append((k, score))
        
        # 选择轮廓系数最高的K值
        optimal_k = max(silhouette_scores, key=lambda x: x[1])[0]
        return optimal_k

    def _analyze_trend(self, prices, dates):
        """分析价格趋势，计算整体趋势和近期趋势"""
        daily_prices = {}
        for price, date in zip(prices, dates):
            if date not in daily_prices:
                daily_prices[date] = []
            daily_prices[date].append(price)
        
        daily_avg_prices = [(date, sum(day_prices)/len(day_prices)) 
                          for date, day_prices in daily_prices.items()]
        daily_avg_prices.sort(key=lambda x: x[0])
        
        if len(daily_avg_prices) >= 3:
            recent_prices = [p for _, p in daily_avg_prices[-3:]]
            recent_trend = (recent_prices[-1] - recent_prices[0]) / recent_prices[0]
        else:
            recent_trend = 0
        
        overall_trend = (daily_avg_prices[-1][1] - daily_avg_prices[0][1]) / daily_avg_prices[0][1]
        
        return {
            'overall_trend': round(overall_trend * 100, 2),  # 整体趋势（百分比）
            'recent_trend': round(recent_trend * 100, 2),    # 近期趋势（百分比）
            # 'daily_avg_prices': [                            # 日均价格列表
            #     {'date': date, 'avg_price': round(avg_price, 2)}  # 日期和均价
            #     for date, avg_price in daily_avg_prices
            # ]
        }

    def analyze_price_thresholds(self, json_data: str) -> dict:
        """分析价格阈值，用于捡漏策略，结合KMeans分析结果和价格趋势"""
        data = json.loads(json_data)
        trade_list = data['data']['tradeDataList']
        
        price_time_pairs = [(float(item['price']), item['localDate']) for item in trade_list]
        price_time_pairs.sort(key=lambda x: x[1])  
        
        prices = [p for p, _ in price_time_pairs]
        dates = [t for _, t in price_time_pairs]
        
        X = np.array(prices).reshape(-1, 1)
        
        # 自动确定最优聚类数量
        n_clusters = self._find_optimal_clusters(X)
        print(f"自动确定的最优聚类数量: {n_clusters}")
            
        kmeans = KMeans(n_clusters=n_clusters, random_state=42)
        kmeans.fit(X)
        
        labels = kmeans.labels_
        centers = kmeans.cluster_centers_.flatten()
        
        cluster_stds = []
        for i in range(n_clusters):
            cluster_prices = [p for p, l in zip(prices, labels) if l == i]
            cluster_stds.append(np.std(cluster_prices) if cluster_prices else 0)
        
        cluster_info = sorted(zip(range(n_clusters), centers, cluster_stds), key=lambda x: x[1])
        
        cluster_ranges = []
        for idx, mean, std in cluster_info:
            cluster_prices = [p for p, l in zip(prices, labels) if l == idx]
            if cluster_prices:
                price_counts = {}
                for p in cluster_prices:
                    rounded_price = round(p, 2)
                    price_counts[rounded_price] = price_counts.get(rounded_price, 0) + 1
                
                max_volume_price = max(price_counts.items(), key=lambda x: x[1])[0]
                
                cluster_ranges.append({
                    'cluster_id': idx,                # 聚类ID
                    'mean': mean,                     # 均值
                    'std': std,                       # 标准差
                    'min_value': min(cluster_prices), # 最小值
                    'max_value': max(cluster_prices), # 最大值
                    'sample_size': len(cluster_prices), # 样本数量
                    'max_volume_price': max_volume_price, # 最高成交量价格
                    'silhouette_score': silhouette_score(X, labels) if len(set(labels)) > 1 else 0  # 轮廓系数
                })
        
        # 确保有足够的聚类
        if len(cluster_ranges) < 2:
            print("警告：聚类数量不足，可能会影响分析结果")
            return {
                "error": "数据不足以进行聚类分析",
                "suggestion": "请确保有足够的价格数据"
            }
        
        trend_analysis = self._analyze_trend(prices, dates)
        
        # 获取高价位段的最低价格作为基准目标售价
        high_cluster = cluster_ranges[-1]
        target_price = high_cluster['min_value']
        
        # 根据趋势调整目标售价
        trend = trend_analysis['overall_trend'] / 100  # 转换为小数
        
        if trend < -0.1:  # 下跌趋势明显
            # 下跌趋势中，目标价格略微下调
            target_price = target_price * (1 + trend * 0.2)  # 仅轻微调整
        elif trend > 0.1:  # 上涨趋势明显
            # 上涨趋势中保持原价
            pass
        
        # 计算价格区间的紧凑程度
        min_price = min(prices)
        max_price = max(prices)
        price_range_ratio = (max_price - min_price) / min_price  # 价格区间范围比例
        
        # 根据趋势调整利润率和安全边际
        price_volatility = np.std(prices) / np.mean(prices)  # 价格波动率
        
        # 根据价格区间紧凑程度调整基础利润率和安全边际
        if price_range_ratio < 0.1:  # 价格区间很紧凑（最高价比最低价高不到10%）
            base_profit_rate = max(0.01, min(0.03, price_volatility))  # 降低利润率范围到1%-3%
            base_safety_margin = max(0.005, min(0.02, price_volatility * 0.6))  # 降低安全边际到0.5%-2%
        else:
            base_profit_rate = max(0.03, min(0.08, price_volatility))  # 保持原有范围3%-8%
            base_safety_margin = max(0.02, min(0.05, price_volatility * 0.6))  # 保持原有范围2%-5%
        
        # 根据趋势调整参数
        trend_adjustment = abs(trend_analysis['recent_trend']) / 100  # 转换为小数
        if trend_analysis['recent_trend'] < 0:  # 下跌趋势
            min_profit_rate = base_profit_rate + trend_adjustment  # 增加要求的利润率
            safety_margin = base_safety_margin + trend_adjustment  # 增加安全边际
        else:  # 上涨或平稳趋势
            min_profit_rate = base_profit_rate
            safety_margin = base_safety_margin
        
        # 计算理论最高买入价格
        theoretical_max_price = target_price / (1 + min_profit_rate + safety_margin)
        
        # 如果理论价格低于历史最低价，则基于历史最低价计算
        if theoretical_max_price < min_price:
            theoretical_max_price = min_price * (1 + min_profit_rate)  # 在历史最低价基础上加上最小利润空间
        
        # 获取低价区间的信息
        low_cluster = cluster_ranges[0]
        
        
        # 建议的捡漏价格范围
        low_cluster_mean = low_cluster['mean']
        low_cluster_std = low_cluster['std']
        
        # 动态计算建议价格范围
        suggested_upper = min(theoretical_max_price, low_cluster_mean + low_cluster_std)
        
        # 计算捡漏上限价格以下的总体成功率
        snipe_upper_limit = suggested_upper  # 使用建议捡漏价格作为捡漏上限
        
        # 统计在捡漏上限价格以下的交易次数
        trades_below_limit = len([p for p in prices if p <= snipe_upper_limit])
        if trades_below_limit > 0:
            # 统计这些交易后能获得利润的次数（价格至少上涨到捡漏上限）
            successful_trades = len([p for p in prices if p >= snipe_upper_limit])
            # 计算总体成功率并转换为百分比
            success_rate = (successful_trades / len(prices)) * 100
            success_rates = {
                "success_rate": f"{round(success_rate, 1)}%",        # 捡漏成功率
                "trades_below_threshold": trades_below_limit,        # 低于捡漏价的交易数
                "trades_above_threshold": successful_trades,         # 高于捡漏价的交易数
                "total_trades": len(prices)                         # 总交易数
            }
        else:
            success_rates = {
                "success_rate": "0%",                               # 捡漏成功率
                "trades_below_threshold": 0,                        # 低于捡漏价的交易数
                "trades_above_threshold": 0,                        # 高于捡漏价的交易数
                "total_trades": len(prices)                         # 总交易数
            }
        
        return {
            "trend_analysis": trend_analysis,                       # 趋势分析
            "cluster_analysis": cluster_ranges,                     # 聚类分析
            "suggested_snipe_price": round(suggested_upper, 2),     # 建议捡漏价格
            "theoretical_max_buy_price": round(theoretical_max_price, 2),  # 理论最高买入价格
            "target_sell_price": round(target_price, 2),           # 目标售价
            # "min_profit_rate": round(min_profit_rate * 100, 1),    # 预期最低利润率
            # "safety_margin": round(safety_margin * 100, 1),        # 安全边际
            "historical_success_rate": success_rates,               # 历史成功率
            "price_range_compactness": round((max(prices) - min(prices)) / min(prices) * 100, 1),  # 价格区间紧凑度
            "volatility": round(np.std(prices) / np.mean(prices) * 100, 1),  # 波动率
            "historical_price_range": {                            # 历史价格范围
                "lowest_price": round(min(prices), 2),             # 最低价
                "highest_price": round(max(prices), 2)             # 最高价
            }
        }

if __name__ == "__main__":
    try:
        with open("sample_trade_data.json", "r", encoding="utf-8") as f:
            json_data = f.read()
        
        analyzer = ItemPricingStrategy()
        threshold_result = analyzer.analyze_price_thresholds(json_data)
        
        print("\n价格阈值分析结果:")
        print(json.dumps(threshold_result, ensure_ascii=False, indent=2))

    except Exception as e:
        print(f"分析过程中出现错误: {str(e)}")
